home *** CD-ROM | disk | FTP | other *** search
- /***********************************************************
- Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum,
- Amsterdam, The Netherlands.
-
- All Rights Reserved
-
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation, and that the names of Stichting Mathematisch
- Centrum or CWI not be used in advertising or publicity pertaining to
- distribution of the software without specific, written prior permission.
-
- STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
- THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
- FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
- OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ******************************************************************/
-
- /*
- ** Partially derived from tifftopnm.c and pnmtotiff.c, which were written
- ** by Jeff Poskanzer, who in turn derived them from ras2tif.c and tis2ras.c,
- ** which are:
- **
- ** Copyright (c) 1990 by Sun Microsystems, Inc.
- **
- ** Author: Patrick J. Naughton
- ** naughton@wind.sun.com
- **
- ** Permission to use, copy, modify, and distribute this software and its
- ** documentation for any purpose and without fee is hereby granted,
- ** provided that the above copyright notice appear in all copies and that
- ** both that copyright notice and this permission notice appear in
- ** supporting documentation.
- **
- ** This file is provided AS IS with no warranties of any kind. The author
- ** shall have no liability with respect to the infringement of copyrights,
- ** trade secrets or any patents by this file or any part thereof. In no
- ** event will the author be liable for any lost revenue or profits or
- ** other special, indirect and consequential damages.
- */
-
- /*
- ** Note: the code could do with some optimalization. The inner loop
- ** in tiff_read() is rather big and contains multiple special cases,
- ** which could be separated out or something. Oh well, It'll be faster
- ** than decoding tiff files in python:-)
- */
-
- #include "allobjects.h"
- #include "modsupport.h" /* For getargs() etc. */
- #include "import.h"
-
- #include "tiffio.h"
-
- /* The image formats we support */
- static PyObject *format_rgb, *format_rgb_b2t, *format_grey,
- *format_grey_b2t, *format_choices;
- extern PyObject *getimgformat(); /* Get format by name */
-
- /* TIFF error handling */
-
- char tifferrstr[1000];
- static TIFFErrorHandler prevErr;
- static TIFFErrorHandler prevWarn;
- #define TIFF_END TIFFSetErrorHandler(prevErr); TIFFSetWarningHandler(prevWarn);
- #define TIFF_START prevErr = TIFFSetErrorHandler(my_tifferror); \
- prevWarn = TIFFSetWarningHandler(my_tiffwarning);
-
- static void
- my_tiffwarning(const char *module, const char *fmt, va_list ap)
- {
- /* Ignore warnings */
- }
-
- static void
- my_tifferror(const char *module, const char *fmt, va_list ap)
- {
- char *ptr = tifferrstr;
-
- if ( module ) {
- sprintf(ptr, "%s: ", module);
- ptr += strlen(ptr);
- }
- vsprintf(ptr, fmt, ap);
- }
-
- /* Tiff objects */
- typedef int tifpix; /* I assume this is correct? Always? */
-
- typedef struct {
- PyObject_HEAD
- PyObject *dict; /* Attributes dictionary */
- int is_reader; /* TRUE if this is a reader */
- char *filename; /* filename of the image file */
- TIFF *filep;
- tifpix maxval; /* Max pixel value in tiff file */
- float factor; /* Convert maxval to 0xff */
- unsigned short photomet;/* TIFF "filetype" */
- unsigned short bps; /* bits per sample */
- unsigned short spp; /* samples per pixel */
- } tiffobject;
-
- static PyObject *errobject;
-
- staticforward PyTypeObject Tifftype;
-
- #define is_tiffobject(v) ((v)->ob_type == &Tifftype)
-
- static char doc_tiff[] = "This object reads/writes TIFF files.\n"
- "The 'width', 'height' and 'format' attributes give info about the\n"
- "image data read (or to be written)";
-
- /* Routine to easily obtain C data from the dict python data */
- int
- tiffselfattr(self, name, fmt, ptr, wanterr)
- tiffobject *self;
- char *name;
- char *fmt;
- void *ptr;
- int wanterr;
- {
- PyObject *obj;
- char errbuf[100];
-
- obj = PyDict_GetItemString(self->dict, name);
- if ( obj == NULL ) {
- if ( wanterr ) {
- sprintf(errbuf, "Required attribute '%s' not set", name);
- PyErr_SetString(errobject, errbuf);
- return 0;
- } else {
- PyErr_Clear();
- return 0;
- }
- }
- if ( !PyArg_Parse(obj, fmt, ptr) ) {
- if ( !wanterr )
- PyErr_Clear();
- return 0;
- }
- return 1;
- }
-
- /* Routine to easily insert integer into dictionary */
- tiffsetintattr(self, name, value)
- tiffobject *self;
- char *name;
- int value;
- {
- PyObject *obj;
- int rv;
-
- obj = PyInt_FromLong(value);
- rv = PyDict_SetItemString(self->dict, name, obj);
- Py_DECREF(obj);
- return rv;
- }
-
- static tiffobject *
- newtiffobject()
- {
- tiffobject *xp;
- xp = PyObject_NEW(tiffobject, &Tifftype);
- if (xp == NULL)
- return NULL;
- xp->dict = PyDict_New();
- xp->filename = NULL;
- xp->filep = NULL;
- return xp;
- }
-
- static int
- inittiffreader(self, name)
- tiffobject *self;
- char *name;
- {
- char *name_copy;
- int cols, rows;
- unsigned short bps, spp, photomet;
- tifpix maxval;
- PyObject *ourformat;
-
- if( (name_copy=malloc(strlen(name)+1)) == NULL ) {
- PyErr_NoMemory();
- return 0;
- }
- strcpy(name_copy, name);
- self->filename = name_copy;
- self->is_reader = 1;
-
- TIFF_START
- if ((self->filep = TIFFOpen(self->filename, "r")) == NULL ) {
- PyErr_SetString(errobject, tifferrstr);
- TIFF_END
- return 0;
- }
-
- if ( ! TIFFGetField( self->filep, TIFFTAG_BITSPERSAMPLE, &bps ) )
- bps = 1;
- if ( ! TIFFGetField( self->filep, TIFFTAG_SAMPLESPERPIXEL, &spp ) )
- spp = 1;
- if ( ! TIFFGetField( self->filep, TIFFTAG_PHOTOMETRIC, &photomet ) ) {
- PyErr_SetString(errobject, "No photometric tag");
- TIFF_END
- return 0;
- }
-
- switch ( spp ) {
- case 1:
- case 3:
- case 4:
- break;
-
- default:
- PyErr_SetString(errobject,
- "can only handle 1-channel gray scale or 1- or 3-channel color" );
- TIFF_END
- return 0;
- }
-
- (void) TIFFGetField( self->filep, TIFFTAG_IMAGEWIDTH, &cols );
- (void) TIFFGetField( self->filep, TIFFTAG_IMAGELENGTH, &rows );
- TIFF_END
-
- maxval = ( 1 << bps ) - 1;
- self->maxval = maxval;
- if ( maxval != 255 ) {
- self->factor = 255.0/(float)maxval;
- /*DBG printf("TIFF factor: %e (%d)\n", self->factor, maxval); */
- }
- self->bps = bps;
- self->spp = spp;
- self->photomet = photomet;
- if ( maxval == 1 && spp == 1 ) {
- ourformat = format_grey;
- } else {
- switch ( photomet ) {
- case PHOTOMETRIC_MINISBLACK:
- ourformat = format_grey;
- break;
-
- case PHOTOMETRIC_MINISWHITE:
- ourformat = format_grey;
- break;
-
- case PHOTOMETRIC_PALETTE:
- PyErr_SetString(errobject, "Cannot handle PALETTE format yet");
- return 0;
-
- case PHOTOMETRIC_RGB:
- ourformat = format_rgb;
- break;
-
- case PHOTOMETRIC_MASK:
- PyErr_SetString(errobject, "Cannot handle PHOTOMETRIC_MASK" );
- return 0;
-
- default:
- PyErr_SetString(errobject, "Unknown photometric type");
- return 0;
- }
- }
-
- TIFF_END
-
- tiffsetintattr(self, "width", cols);
- tiffsetintattr(self, "height", rows);
- #if 0
- tiffsetintattr(self, "bps", (int)bps);
- tiffsetintattr(self, "spp", (int)spp);
- #endif
- PyDict_SetItemString(self->dict, "format", ourformat);
- PyDict_SetItemString(self->dict, "format_choices", format_choices);
- if ( PyErr_Occurred() )
- return 0;
- return 1;
- }
-
- static int
- inittiffwriter(self, name)
- tiffobject *self;
- char *name;
- {
- char *name_copy;
-
- if( (name_copy=malloc(strlen(name)+1)) == NULL ) {
- PyErr_NoMemory();
- return 0;
- }
- strcpy(name_copy, name);
- self->filename = name_copy;
-
- self->is_reader = 0;
- PyDict_SetItemString(self->dict, "format", format_rgb);
- PyDict_SetItemString(self->dict, "format_choices", format_choices);
- if( PyErr_Occurred())
- return 0;
- return 1;
- }
-
- /* Tiff methods */
-
- static void
- tiff_dealloc(xp)
- tiffobject *xp;
- {
- Py_XDECREF(xp->dict);
- if( xp->filename )
- free(xp->filename);
- if( xp->filep )
- TIFFClose(xp->filep);
- PyMem_DEL(xp);
- }
-
- static char doc_read[] = "Read the actual data, returns a string";
-
- static PyObject *
- tiff_read(self, args)
- tiffobject *self;
- PyObject *args;
- {
- int w, h, toptobottom, havegrey, wantgrey, rowlen;
- int row, col, bitsleft;
- PyObject *rv;
- long *rgbdatap=0;
- char *greydatap=0;
- tifpix greysample, redsample, greensample, bluesample, maxval;
- PyObject *fmt;
- unsigned char *buf, *inP;
- unsigned short bps, spp, photomet;
-
- if (!PyArg_ParseTuple(args,""))
- return NULL;
- if (!self->is_reader) {
- PyErr_SetString(errobject, "Cannot read() from writer object");
- return NULL;
- }
- /* XXXX Read data and return it */
- /* XXXX Get args from self->dict and write the data */
- if ( !tiffselfattr(self, "width", "i", &w, 1) ||
- !tiffselfattr(self, "height", "i", &h, 1) ||
- !tiffselfattr(self, "format", "O", &fmt, 1) )
- return NULL;
- if ( fmt == format_rgb || fmt == format_grey )
- toptobottom = 1;
- else if ( fmt == format_rgb_b2t || fmt == format_grey_b2t )
- toptobottom = 0;
- else {
- PyErr_SetString(errobject, "Unsupported image format");
- return NULL;
- }
- if ( fmt == format_rgb || fmt == format_rgb_b2t )
- wantgrey = 0;
- else
- wantgrey = 1;
-
- rv = 0;
-
- rowlen = w;
-
- if ( wantgrey ) {
- rowlen = (rowlen+3) & ~3; /* pad to 32-bit boundary */
- if ( (rv=PyString_FromStringAndSize(0, rowlen*h)) == NULL )
- return NULL;
- greydatap = PyString_AsString(rv);
- rgbdatap = 0;
- } else {
- if ( (rv=PyString_FromStringAndSize(0, rowlen*h*4)) == NULL )
- return NULL;
- rgbdatap = (long *)PyString_AsString(rv);
- greydatap = 0;
- }
-
- if ( !toptobottom ) {
- greydatap = greydatap + rowlen*(h-1);
- rgbdatap = rgbdatap + rowlen*(h-1);
- rowlen = -rowlen;
- }
-
- havegrey = (self->photomet != PHOTOMETRIC_RGB);
- bps = self->bps;
- maxval = self->maxval;
- spp = self->spp;
- photomet = self->photomet;
-
- buf = (unsigned char *)malloc(TIFFScanlineSize(self->filep));
- if ( buf == NULL ) {
- Py_DECREF(rv);
- PyErr_NoMemory();
- return NULL;
- }
-
- TIFF_START
-
- #define NEXTSAMPLE(which) \
- { \
- if ( bitsleft == 0 ) \
- { \
- ++inP; \
- bitsleft = 8; \
- } \
- bitsleft -= bps; \
- which = ( *inP >> bitsleft ) & maxval; \
- }
-
- row = 0;
- while( row < h ) {
- if ( TIFFReadScanline( self->filep, buf, row, 0) < 0) {
- PyErr_SetString(errobject, tifferrstr);
- free(buf);
- TIFF_END
- return NULL;
- }
- inP = buf;
- bitsleft = 8;
-
- for( col=0; col<w; col++ ) {
- switch(photomet) {
- case PHOTOMETRIC_MINISBLACK:
- NEXTSAMPLE(greysample);
- break;
- case PHOTOMETRIC_MINISWHITE:
- NEXTSAMPLE(greysample);
- greysample = maxval - greysample;
- break;
- case PHOTOMETRIC_RGB:
- NEXTSAMPLE(redsample);
- NEXTSAMPLE(greensample);
- NEXTSAMPLE(bluesample);
- if ( spp == 4 )
- NEXTSAMPLE(greysample); /* Ignored alpha */
- break;
- default:
- PyErr_SetString(errobject, "Unknown photometric (cannot happen)");
- free(buf);
- TIFF_END
- return NULL;
- }
- if ( !havegrey && wantgrey ) {
- greysample = (int)(0.299*redsample+0.587*greensample+
- 0.114*bluesample);
- if ( greysample > 255 ) greysample = 255;
- } else if ( havegrey && !wantgrey ) {
- redsample = greensample = bluesample = greysample;
- }
- if ( wantgrey ) {
- if ( maxval != 255 ) {
- greysample = (int)((float)greysample*self->factor);
- if ( greysample > 255 )
- greysample = 255;
- }
- greydatap[col] = greysample;
- } else {
- if ( maxval != 255 ) {
- redsample = (int)((float)redsample*self->factor);
- if ( redsample > 255 )
- redsample = 255;
- greensample = (int)((float)greensample*self->factor);
- if ( greensample > 255 )
- greensample = 255;
- bluesample = (int)((float)bluesample*self->factor);
- if ( bluesample > 255 )
- bluesample = 255;
- }
- rgbdatap[col] = redsample | (greensample<<8) |
- (bluesample<<16);
- }
- }
- /* Zero-out remaining bytes */
- if ( wantgrey )
- while( col < rowlen )
- greydatap[col++] = 0;
- rgbdatap += rowlen;
- greydatap += rowlen;
- row++;
- }
- TIFF_END
- free(buf);
- return rv;
- }
-
- static char doc_write[] = "Write (string) data to the TIFF file.";
-
- static PyObject *
- tiff_write(self, args)
- tiffobject *self;
- PyObject *args;
- {
- long *rgbdata;
- char *greydata;
- int datalen, lenwanted;
- unsigned char *buf, *tP;
- int i, w, h, rowlen, row;
- PyObject *fmt;
- long rgbpixel;
- unsigned short photomet, spp;
- int bytesperrow;
- long rowsperstrip;
- TIFF *filep;
-
- if (!PyArg_ParseTuple(args, "s#", &greydata, &datalen))
- return NULL;
- if (self->is_reader) {
- PyErr_SetString(errobject, "Cannot write() to reader object");
- return NULL;
- }
- /* XXXX Get args from self->dict and write the data */
- if ( !tiffselfattr(self, "width", "i", &w, 1) ||
- !tiffselfattr(self, "height", "i", &h, 1) ||
- !tiffselfattr(self, "format", "O", &fmt, 1) )
- return NULL;
-
- rowlen = w;
- if ( fmt == format_rgb || fmt == format_rgb_b2t ) {
- spp = 3;
- photomet = PHOTOMETRIC_RGB;
- lenwanted = w*h*4;
- rgbdata = (long *)greydata;
- greydata = 0;
- } else if ( fmt == format_grey || fmt == format_grey_b2t ) {
- spp = 1;
- photomet = PHOTOMETRIC_MINISBLACK;
- rowlen = (w+3) &~3;
- lenwanted = rowlen*h;
- rgbdata = 0;
- } else {
- PyErr_SetString(errobject, "Unsupported image format");
- return NULL;
- }
-
- if( datalen != lenwanted ) {
- PyErr_SetString(errobject, "Incorrect datasize");
- return NULL;
- }
-
- if ( fmt == format_rgb_b2t || fmt == format_grey_b2t ) {
- rgbdata = rgbdata + rowlen*(h-1);
- greydata = greydata + rowlen*(h-1);
- rowlen = -rowlen;
- }
-
- bytesperrow = spp*w;
- rowsperstrip = 8192 / bytesperrow; /* ??? from pnmtotiff */
-
- if( (buf = malloc(bytesperrow)) == NULL ) {
- PyErr_NoMemory();
- return NULL;
- }
-
- TIFF_START
- if ((filep = TIFFOpen(self->filename, "w")) == NULL) {
- PyErr_SetString(errobject, tifferrstr);
- TIFF_END
- return 0;
- }
-
- TIFFSetField(filep, TIFFTAG_IMAGEWIDTH, w);
- TIFFSetField(filep, TIFFTAG_IMAGELENGTH, h);
- TIFFSetField(filep, TIFFTAG_BITSPERSAMPLE, 8);
- TIFFSetField(filep, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); /*XXX*/
- TIFFSetField(filep, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
- TIFFSetField(filep, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
- TIFFSetField(filep, TIFFTAG_PHOTOMETRIC, photomet);
- TIFFSetField(filep, TIFFTAG_SAMPLESPERPIXEL, spp);
- TIFFSetField(filep, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
- TIFFSetField(filep, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
- TIFFSetField(filep, TIFFTAG_SOFTWARE, "Python TIFF module");
-
-
- row = 0;
- while( row < h ) {
- tP = buf;
- for(i=0; i<w; i++) {
- if ( photomet == PHOTOMETRIC_RGB ) {
- rgbpixel = rgbdata[i];
- *tP++ = rgbpixel & 0xff;
- *tP++ = (rgbpixel>>8) & 0xff;
- *tP++ = (rgbpixel>>16) & 0xff;
- } else {
- *tP++ = greydata[i];
- }
- }
- if ( TIFFWriteScanline(filep, buf, row, 0) < 0 ) {
- free(buf);
- PyErr_SetString(errobject, tifferrstr);
- return 0;
- }
- rgbdata += rowlen;
- greydata += rowlen;
- row = row+1;
- }
- TIFFFlushData(filep);
- TIFFClose(filep);
- free(buf);
- Py_INCREF(Py_None);
- return Py_None;
- }
-
- static struct PyMethodDef tiff_methods[] = {
- {"read", (PyCFunction)tiff_read, 1, doc_read},
- {"write", (PyCFunction)tiff_write, 1, doc_write},
- {NULL, NULL} /* sentinel */
- };
-
- static PyObject *
- tiff_getattr(xp, name)
- tiffobject *xp;
- char *name;
- {
- PyObject *v;
-
- if (xp->dict != NULL) {
- if ( strcmp(name, "__dict__") == 0 ) {
- Py_INCREF(xp->dict);
- return xp->dict;
- }
- if ( strcmp(name, "__doc__") == 0 ) {
- return PyString_FromString(doc_tiff);
- }
- v = PyDict_GetItemString(xp->dict, name);
- if (v != NULL) {
- Py_INCREF(v);
- return v;
- }
- }
- return Py_FindMethod(tiff_methods, (PyObject *)xp, name);
- }
-
- static int
- tiff_setattr(xp, name, v)
- tiffobject *xp;
- char *name;
- PyObject *v;
- {
- if (xp->dict == NULL) {
- xp->dict = PyDict_New();
- if (xp->dict == NULL)
- return -1;
- }
- if (v == NULL) {
- int rv = PyDict_DelItemString(xp->dict, name);
- if (rv < 0)
- PyErr_SetString(PyExc_AttributeError,
- "delete non-existing imgtiff attribute");
- return rv;
- }
- else
- return PyDict_SetItemString(xp->dict, name, v);
- }
-
- static PyTypeObject Tifftype = {
- PyObject_HEAD_INIT(&PyType_Type)
- 0, /*ob_size*/
- "imgtiff", /*tp_name*/
- sizeof(tiffobject), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- /* methods */
- (destructor)tiff_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- (getattrfunc)tiff_getattr, /*tp_getattr*/
- (setattrfunc)tiff_setattr, /*tp_setattr*/
- 0, /*tp_compare*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash*/
- };
-
- static char doc_newreader[] =
- "Return an object that reads the TIFF file passed as argument";
-
- static PyObject *
- tiff_newreader(self, args)
- PyObject *self;
- PyObject *args;
- {
- char *filename;
- tiffobject *obj;
-
- if (!PyArg_ParseTuple(args, "s", &filename))
- return NULL;
- if ((obj = newtiffobject()) == NULL)
- return NULL;
- if ( !inittiffreader(obj, filename) ) {
- tiff_dealloc(obj);
- return NULL;
- }
- return (PyObject *)obj;
- }
-
- static char doc_newwriter[] =
- "Return an object that writes the TIFF file passed as argument";
-
- static PyObject *
- tiff_newwriter(self, args)
- PyObject *self;
- PyObject *args;
- {
- char *filename;
- tiffobject *obj;
-
- if (!PyArg_ParseTuple(args, "s", &filename))
- return NULL;
- if ((obj = newtiffobject()) == NULL)
- return NULL;
- if ( !inittiffwriter(obj, filename) ) {
- tiff_dealloc(obj);
- return NULL;
- }
- return (PyObject *)obj;
- }
-
-
- /* List of functions defined in the module */
-
- static struct PyMethodDef tiff_module_methods[] = {
- {"reader", tiff_newreader, 1, doc_newreader},
- {"writer", tiff_newwriter, 1, doc_newwriter},
- {NULL, NULL} /* sentinel */
- };
-
-
- /* Initialization function for the module (*must* be called initimgtiff) */
- static char doc_imgtiff[] = "Module to read and write TIFF image files";
-
- void
- initimgtiff()
- {
- PyObject *m, *d, *x, *formatmodule, *formatdict;
-
- /* Create the module and add the functions */
- m = Py_InitModule("imgtiff", tiff_module_methods);
-
- /* Add some symbolic constants to the module */
- d = PyModule_GetDict(m);
- errobject = PyString_FromString("imgtiff.error");
- PyDict_SetItemString(d, "error", errobject);
- x = PyString_FromString(doc_imgtiff);
- PyDict_SetItemString(d, "__doc__", x);
-
- /* Get supported formats */
- if ((formatmodule = PyImport_ImportModule("imgformat")) == NULL)
- Py_FatalError("imgtiff depends on imgformat");
- if ((formatdict = PyModule_GetDict(formatmodule)) == NULL)
- Py_FatalError("imgformat has no dict");
-
-
- format_rgb = PyDict_GetItemString(formatdict,"rgb");
- format_rgb_b2t = PyDict_GetItemString(formatdict,"rgb_b2t");
- format_grey = PyDict_GetItemString(formatdict,"grey");
- format_grey_b2t = PyDict_GetItemString(formatdict,"grey_b2t");
- format_choices = Py_BuildValue("(OOOO)", format_rgb, format_rgb_b2t,
- format_grey, format_grey_b2t);
-
- /* Check for errors */
- if (PyErr_Occurred())
- Py_FatalError("can't initialize module imgtiff");
- }
-